#include "appmysql.h"
#include "appmysqlconfig.h"
#include "CTTimeEscapeCheck.h"

CTLIB_SO_FUNC(CAppMysql)

CAppMysql::CAppMysql()
:m_iOpType(0)
{

}

CAppMysql::~CAppMysql()
{

}

int CAppMysql::Init(void *pData)
{
	CT_ASSERT(pData);
	CONF->LoadConfig((const char*)pData);
	CT_TRACE(("so load config ok"));

	return ConnectToDB();
}

int CAppMysql::Do(const CEnpNetHead& stHead, const char* pszReqBuf, int iReqLen, 
				  char* pszAnsBuf, int iAnsBufLen, int& iAnsLen)
{
	CT_TRACE(("RecvMsg: len=%d msg=%s AnsBufLen=%d", iReqLen, pszReqBuf, iAnsBufLen));

	int iRet = InitReq(pszReqBuf, iReqLen);
	if (iRet != RET_OK)
	{
		SendAns(iRet, pszAnsBuf, iAnsBufLen, iAnsLen);
	}

	iRet = DealReq();
	if (iRet != RET_OK)
	{
		SendAns(iRet, pszAnsBuf, iAnsBufLen, iAnsLen);
	}

	SendAns(iRet, pszAnsBuf, iAnsBufLen, iAnsLen);
	return iRet;
}

int CAppMysql::Exit()
{
	DisconnectFromDB();
	return RET_OK;
}

int CAppMysql::ConnectToDB()
{
	CT_TRACE(("connect mysql: host=%s user=%s pass=%s port=%d socket=%s", 
		CONF->DBHost, CONF->DBUser, CONF->DBPass, CONF->DBPort, CONF->DBSocket));

	if (m_stDb.IsConnected())
	{
		CT_WARNING(("db is connected"));
		return 0;
	}

	try
	{
		m_stDb.Connect(CONF->DBHost, CONF->DBUser, CONF->DBPass, CONF->DBPort, CONF->DBSocket, false);
		m_stDb.Query("set names 'utf8'");
        //m_stDb.Query("set charset utf8'");
	}
	catch (CTException& e)
	{
		CT_FATAL(("exception: %d, %s", e.GetErrorCode(), e.GetErrorMsg()));
		return RET_SYSTEM_FAIL;
	}
	
	CT_TRACE(("connect to db ok"));
	return RET_OK;
}

int CAppMysql::DisconnectFromDB()
{
	CT_TRACE(("disconnect from db"));

	if (!m_stDb.IsConnected())
	{
		return RET_OK;
	}
	m_stDb.Close();
	return RET_OK;
}

int CAppMysql::InitReq(const char* pszReqBuf, int iReqLen)
{
	m_stCodeStream.Attach((char*)pszReqBuf, (unsigned short)(iReqLen & 0xFFFF));
	CodeConvert(m_stCodeStream, m_stMsgHead, NULL, bin_decode());

	if(m_stMsgHead.shMsgID != ID_DB_SQL
		|| m_stMsgHead.shMsgType != EMT_REQUEST)
	{
		CT_WARNING(("req head invalid, msgid = %d, msgtype = %d", m_stMsgHead.shMsgID, m_stMsgHead.shMsgType));
		return RET_INVALID_PARAM;
	}

	CodeConvert(m_stCodeStream, m_stReqSql, NULL, bin_decode());

	if (m_stCodeStream.m_iRet)
	{
		CT_WARNING(("CodeConvert failed, ret=%d", m_stCodeStream.m_iRet));
		return RET_INVALID_PARAM;
	}

	if (m_stMsgHead.shMsgID != ID_DB_SQL || m_stMsgHead.shMsgType != EMT_REQUEST)
	{
		CT_WARNING(("msghead(%d, %d) invalid", m_stMsgHead.shMsgID, m_stMsgHead.shMsgType));
		return RET_INVALID_PARAM;
	}

	CT_TRACE(("init sqlreq ok, sql : %s", m_stReqSql.GetSqlBuffer()));
	return RET_OK;
}

int CAppMysql::DealReq()
{
	string sTemp(m_stReqSql.stSQLMen.GetBuffer());
	int iTrimSize = sTemp.find_first_not_of(" \r\n\t");
	if (iTrimSize)
	{
		if(m_stReqSql.Remove(iTrimSize) != 0)
		{
			CT_WARNING((""));
			return RET_SYSTEM_FAIL;
		}
	}

	// 确定SQL语句的类型
	CT_TRACE(("sql: %s", m_stReqSql.GetSqlBuffer()));
	if (strncasecmp(m_stReqSql.GetSqlBuffer(), "select", 6) == 0)
	{
		m_iOpType = MYSQL_SELECT;
	}
	else if (strncasecmp(m_stReqSql.GetSqlBuffer(), "insert", 6) == 0)
	{
		m_iOpType = MYSQL_INSERT;
	}
	else if (strncasecmp(m_stReqSql.GetSqlBuffer(), "update", 6) == 0)
	{
		m_iOpType = MYSQL_UPDATE;
	}
	else if (strncasecmp(m_stReqSql.GetSqlBuffer(), "delete", 6) == 0)
	{
		m_iOpType = MYSQL_DELETE;
	}
	else if (strncasecmp(m_stReqSql.GetSqlBuffer(), "replace", 7) == 0)
	{
		m_iOpType = MYSQL_REPLACE;
	}
	else
	{
		return RET_INVALID_PARAM;
	}

    static CTTimeEscapeCheck stTimeChecker;
    stTimeChecker.Reset();
	//执行sql
	try
	{
		m_stDb.Query(m_stReqSql.stSQLMen);
	}
	catch (CTException& e)
	{
		CT_FATAL(("exception: %d, %s", e.GetErrorCode(), e.GetErrorMsg()));
		return RET_SYSTEM_FAIL;
	}
	CT_INFO(("exec sql ok, use time %dms, sql is %s", stTimeChecker.CheckMSec(), m_stReqSql.GetSqlBuffer()));
	return RET_OK;
}

int CAppMysql::SendAns(int iResult, char* pszAnsBuf, int iAnsBufLen, int& iAnsLen)
{
	CT_TRACE(("begin send ans, ret = %d", iResult));
	unsigned short ushAnsBufLen = (unsigned short)(iAnsBufLen & 0xFFFF);
	int iRet = m_stCodeStream.Attach(pszAnsBuf, ushAnsBufLen);
	if (iRet != RET_OK)
	{
		return iRet;
	}

	m_stMsgHead.shMsgType = EMT_ANSWER;
	CodeConvert(m_stCodeStream, m_stMsgHead, NULL, bin_encode());

	if (iResult)
	{
		m_stAnsSql.m_iResult = iResult;
		CodeConvert(m_stCodeStream, m_stAnsSql, NULL, bin_encode());
	}
	else
	{
		MySQLEncode(m_stCodeStream, m_stDb, m_iOpType);
		iRet = m_stCodeStream.m_iRet;
		if (iRet) 
		{
			m_stCodeStream.m_ushPos = sizeof(m_stMsgHead);   //如果出现错误，则需重新编码返回结果
			m_stCodeStream.m_iRet = 0;

			m_stAnsSql.m_iResult = m_stCodeStream.m_iRet;
			CodeConvert(m_stCodeStream, m_stAnsSql, NULL, bin_encode());
		}
	}
	iAnsLen = m_stCodeStream.m_ushPos;
	
	if(iRet)
	{
		CT_WARNING(("SendAns error"));
	}
	CT_TRACE(("send ans ok, anslen = %d", iAnsLen));
	return iRet;
}




